/*
 * Copyright (c) 2023. Shanghai HEADING information Engineering Co., Ltd. All rights reserved.
 */

package com.lovely602.boot.bootdemo.controller.java.thread;

import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.lovely602.boot.bootdemo.utils.ThreadPoolHelper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.lovely602.boot.bootdemo.domain.common.RestResponse;

import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lizhixing
 */
@Api(tags = "thread服务")
@RestController
@RequestMapping(value = "/v1/bff/web/thread", produces = "application/json;charset=utf-8")
@Slf4j
public class ThreadController {

  @GetMapping("oom1")
  public void oom1() {

    ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
    // 打印线程池的信息，稍后我会解释这段代码
    printStats(threadPool);
    for (int i = 0; i < 100000000; i++) {
      threadPool.execute(() -> {
        String payload = IntStream.rangeClosed(1, 1000000).mapToObj(__ -> "a")
            .collect(Collectors.joining("")) + UUID.randomUUID();
        try {
          TimeUnit.MINUTES.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        log.info(payload);
      });
    }
  }

  @GetMapping("oom2")
  public void oom2() {

    ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
    // 打印线程池的信息，稍后我会解释这段代码
    printStats(threadPool);
    for (int i = 0; i < 100000000; i++) {
      threadPool.execute(() -> {
        String payload = IntStream.rangeClosed(1, 1000000).mapToObj(__ -> "a")
            .collect(Collectors.joining("")) + UUID.randomUUID();
        try {
          TimeUnit.HOURS.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        log.info(payload);
      });
    }
  }

  @GetMapping("wrong")
  public RestResponse<String> wrong() throws InterruptedException {
    ThreadPoolExecutor threadPool = ThreadPoolHelper.getWrongThreadPool();
    IntStream.rangeClosed(1, 10).forEach(i -> {
      threadPool.execute(() -> {
        try {
          TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
          log.error("线程休眠失败", e);
        }
      });
    });
    return RestResponse.success("ok");
  }

  @GetMapping("right")
  public RestResponse<Integer> right() throws InterruptedException {
    // 使用一个计数器跟踪完成的任务数。
    AtomicInteger atomicInteger = new AtomicInteger();
    // 创建一个具有2个核心线程、5个最大线程、使用容量为10的ArrayBlockingQueue阻塞队列作为工作队列的线程池，
    // 使用默认的AbortPolicy拒绝策略。
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 5, TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(10),
        new ThreadFactoryBuilder().setNameFormat("demo-threadPool-%d").build(),
        new ThreadPoolExecutor.AbortPolicy());

    printStats(threadPool);
    // 每隔1秒提交一次，一共提交20次任务
    IntStream.rangeClosed(1, 20).forEach(i -> {
      try {
        TimeUnit.SECONDS.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      int id = atomicInteger.incrementAndGet();
      try {
        threadPool.submit(() -> {
          log.info("{} started", id);
          // 每个任务耗时10秒
          try {
            TimeUnit.SECONDS.sleep(10);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          log.info("{} finished", id);
        });
      } catch (Exception ex) {
        // 提交出现异常的话，打印出错误信息并为计数器减一
        log.error("error submitting task {}", id, ex);
        atomicInteger.decrementAndGet();
      }
    });

    return RestResponse.success(atomicInteger.intValue());
  }

  private void printStats(ThreadPoolExecutor threadPool) {
    // 该线程一直执行,需执行完手动删除
    Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
      log.info("===============================");
      log.info("Pool Size: {}", threadPool.getPoolSize());
      log.info("Active Threads: {}", threadPool.getActiveCount());
      log.info("Number of Tasks Completed: {}", threadPool.getCompletedTaskCount());
      log.info("Number of Tasks in Queue: {}", threadPool.getQueue().size());
      log.info("===============================");
    }, 0, 1, TimeUnit.SECONDS);
  }

}
